package org.openea.eap.module.obpm.controller.form;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.ApiOperation;
import org.openbpm.base.api.aop.annotion.CatchErr;
import org.openbpm.base.api.constant.IStatusCode;
import org.openbpm.base.api.exception.BusinessException;
import org.openbpm.base.api.query.QueryFilter;
import org.openbpm.base.api.response.impl.ResultMsg;
import org.openbpm.base.core.util.StringUtil;
import org.openbpm.base.core.util.ThreadMapUtil;
import org.openbpm.base.dao.CommonDao;
import org.openbpm.base.db.datasource.DbContextHolder;
import org.openbpm.base.db.model.page.PageResult;
import org.openbpm.base.rest.ControllerTools;
import org.openbpm.base.rest.util.RequestUtil;
import org.openbpm.bus.api.constant.BusinessObjectPersistenceType;
import org.openbpm.bus.api.constant.BusinessPermissionObjType;
import org.openbpm.bus.api.model.*;
import org.openbpm.bus.api.service.IBusinessDataService;
import org.openbpm.bus.api.service.IBusinessObjectService;
import org.openbpm.bus.api.service.IBusinessPermissionService;
import org.openbpm.bus.api.service.IBusinessTableService;
import org.openbpm.bus.model.BusinessTable;
import org.openbpm.form.api.constant.FormStatusCode;
import org.openea.eap.module.obpm.service.custsql.FormCustSqlRelationManager;
import org.openea.eap.module.obpm.service.form.FormDefManager;
import org.openea.eap.module.obpm.model.form.FormDef;
import org.openea.eap.module.obpm.model.form.FormDefData;
import org.openea.eap.module.obpm.service.form.FormDefDataService;
import org.openea.eap.module.obpm.util.form.BusinessTableExcellor;
import org.openbpm.sys.api.groovy.IGroovyScriptEngine;
import org.openbpm.sys.api.model.ISysDataSource;
import org.openbpm.sys.api.service.ISysDataSourceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.Closeable;
import java.io.OutputStream;
import java.util.*;


@RestController
@RequestMapping({"/form/formDefData/"})
public class FormDefDataController
        extends ControllerTools {
    @Autowired
    FormDefDataService formDefDataService;
    @Autowired
    IBusinessDataService businessDataService;
    @Autowired
    IBusinessObjectService businessObjectService;
    @Autowired
    ISysDataSourceService sysDataSourceService;
    @Autowired
    CommonDao<?> commonDao;
    @Autowired
    IBusinessPermissionService businessPermissionService;
    @Autowired
    FormDefManager formDefManager;
    @Autowired
    IBusinessTableService businessTableService;
    @Autowired
    FormCustSqlRelationManager formCustSqlRelationManager;
    @Autowired
    IGroovyScriptEngine groovyScriptEngine;

    @RequestMapping({"getData"})
    @CatchErr(write2response = true, value = "获取FormDefData异常")
    public ResultMsg<FormDefData> getFormDefData(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String key = RequestUtil.getString(request, "key");
        String id = RequestUtil.getString(request, "id", null);
        boolean isSql = RequestUtil.getBoolean(request, "sql", false);
        ThreadMapUtil.put("FormDefDataController_getFormDefData_isSql", Boolean.valueOf(isSql));
        Boolean isReadOnly = Boolean.valueOf(RequestUtil.getBoolean(request, "isReadOnly", false));
        // add parameter "tryNew"
        Boolean supportTryNew = Boolean.valueOf(RequestUtil.getBoolean(request, "tryNew", false));
        FormDefData formDefData = null;
        try {
            formDefData = this.formDefDataService.getByFormDefKey(key, id, isReadOnly);
        } catch (BusinessException e) {
            if (supportTryNew) {
                formDefData = this.formDefDataService.getByFormDefKey(key, null, isReadOnly);
                formDefData.getData().put("id",id);
            } else {
                throw e;
            }
        }
        return getSuccessResult(formDefData);
    }


    @RequestMapping({"saveData"})
    @CatchErr(write2response = true, value = "保存formDef中的data数据异常")
    public ResultMsg<JSONObject> saveData(HttpServletRequest request, HttpServletResponse response, @RequestBody JSONObject data) throws Exception {
        String key = RequestUtil.getString(request, "key");
        //boolean isSql = RequestUtil.getBoolean(request, "sql", false);
        String sqlCode = RequestUtil.getString(request, "sql");
        boolean hasScript = false;
        if(StringUtil.isNotEmpty(sqlCode)){
            hasScript = true;
        }
        JSONObject result = this.formDefDataService.saveFormDefData(data, key, hasScript);
        return getSuccessResult(result,"保存数据成功");
    }


    @RequestMapping({"getList_{boKey}"})
    @CatchErr(write2response = true, value = "获取对话框的列表数据失败")
    public PageResult getList(HttpServletRequest request, HttpServletResponse response, @PathVariable("boKey") String boKey) throws Exception {
        QueryFilter queryFilter = getQueryFilter(request);

        IBusinessObject businessObject = this.businessObjectService.getFilledByKey(boKey);
        IBusinessTable businessTable = businessObject.getRelation().getTable();
        ISysDataSource sysDataSource = this.sysDataSourceService.getByKey(businessTable.getDsKey());

        DbContextHolder.setDataSource(sysDataSource.getKey(), sysDataSource.getDbType());
        String sql = "select * from " + businessTable.getName();
        List<?> list = this.commonDao.queryForListPage(sql, queryFilter);
        return new PageResult(list);
    }

    @RequestMapping(value={"removeData/{formKey}/{id}"}, method = {RequestMethod.POST, RequestMethod.GET, RequestMethod.DELETE})
    @CatchErr(write2response = true, value = "删除formDef中的data数据异常")
    @ApiOperation(
            value = "删除formDef中的data数据",
            notes = "删除formDef中的data数据(delField/delValue表示逻辑删除的字段和值)"
    )
    public ResultMsg removeData(@PathVariable(value = "formKey", required = false) String formKey,
                                @PathVariable(value = "id", required = false) String id,
                                @RequestParam(value = "logicDel", required = false) Boolean logicDel,
                                @RequestParam(value = "delField", required = false) String delField,
                                @RequestParam(value = "delValue", required = false) String delValue
    ) throws Exception {
        if (StringUtil.isEmpty(formKey)) {
            throw new BusinessException("formKey 不能为空", (IStatusCode) FormStatusCode.PARAM_ILLEGAL);
        }
        if (StringUtil.isEmpty(id)) {
            throw new BusinessException("ID 不能为空", (IStatusCode) FormStatusCode.PARAM_ILLEGAL);
        }
        FormDef formDef = this.formDefManager.getByKey(formKey);
        String boKey = formDef.getBoKey();

        IBusinessPermission permission = this.businessPermissionService.getByObjTypeAndObjVal(BusinessPermissionObjType.FORM.getKey(), formKey, formDef.getBoKey(), true);
        IBusinessObject businessObject = this.businessObjectService.getFilledByKey(boKey);
        businessObject.setPermission(permission.getBusObj(boKey));

        // 逻辑删除(临时方案，需要优化）
        if (!StringUtils.isEmpty(delField)) {
            if (StringUtils.isEmpty(delValue)) {
                delValue = "1";
            }
            IBusinessData bd = this.businessDataService.loadData(businessObject, id);
            bd.put(delField, delValue);
            this.businessDataService.saveData(bd);
        } else {
            this.businessDataService.removeData(businessObject, id);
        }

        return getSuccessResult("删除成功！");
    }


    @RequestMapping(value = {"importExcel"}, method = {RequestMethod.POST})
    @CatchErr("excel导入失败")
    public ResultMsg<List<Map<String, Object>>> importExcel(@RequestParam("file") MultipartFile file, @RequestParam("tableKey") String tableKey) throws Exception {
        ExcelReader reader = ExcelUtil.getReader(file.getInputStream());
        List<Map<String, Object>> readAll = reader.readAll();
        IBusinessTable table = this.businessTableService.getFilledByKey(tableKey);
        return getSuccessResult((new BusinessTableExcellor(table)).fromExcel(readAll));
    }

    @RequestMapping(value = {"importBoExcel"}, method = {RequestMethod.POST})
    @CatchErr("excel导入失败")
    public ResultMsg<List<Map<String, Object>>> importBoExcel(@RequestParam("file") MultipartFile file, @RequestParam("tableKey") String tableKey) throws Exception {
        ExcelReader reader = ExcelUtil.getReader(file.getInputStream());
        List<Map<String, Object>> readAll = reader.readAll();
        IBusinessTable table = this.businessTableService.getFilledByKey(tableKey);
        // TODO importBoExcel
        return getSuccessResult((new BusinessTableExcellor(table)).fromExcel(readAll));
    }

    @RequestMapping(value = {"exportExcel"}, method = {RequestMethod.POST})
    @CatchErr("excel导出失败")
    public void exportExcel(HttpServletRequest request, HttpServletResponse response, @RequestParam("list") String listStr, @RequestParam("tableKey") String tableKey, @RequestParam("columnKeys") String columnKeys) throws Exception {
        JSONArray list = JSONArray.parseArray(listStr);
        doExportExcel(response, list, null, tableKey, columnKeys);
    }

    @RequestMapping(value = {"exportBoExcel"}, method = {RequestMethod.POST})
    @CatchErr("excel导出失败")
    public void exportBoExcel(HttpServletRequest request, HttpServletResponse response,
                              @RequestParam(value="boKey", required = false) String boKey, @RequestParam(value = "tableKey", required = false) String tableKey, @RequestParam("columnKeys") String columnKeys) throws Exception {
        doExportExcel(response, null, boKey, tableKey, columnKeys);
    }

    // 导出数据excel
    protected void doExportExcel(HttpServletResponse response, JSONArray list, String boKey, String tableKey, String columnKeys) throws Exception {
        IBusinessObject busObj = null;
        if(StringUtil.isNotEmpty(boKey)){
            busObj = this.businessObjectService.getByKey(boKey);
            if(!BusinessObjectPersistenceType.DB.getKey().equals(busObj.getPersistenceType())){
                throw new BusinessException("只支持主表数据导出");
            }
        }
        if(StringUtil.isEmpty(tableKey) && busObj!=null){
            tableKey = busObj.getRelation().getTableKey();
        }
        IBusinessTable table = this.businessTableService.getFilledByKey(tableKey);
        String[] lmKeys = columnKeys.split(",");
        if(list==null){
            //BusinessDataPersistenceServiceFactory.getService(BusinessObjectPersistenceType.DB.getKey());
            List<Map<String, Object>> listData = this.formDefDataService.loadDataList((BusinessTable)table, Arrays.asList(lmKeys), new HashMap(0));
            list = new JSONArray();
            list.addAll(listData);
        }
        ExcelWriter writer = ExcelUtil.getWriter();
        List<Map<String, Object>> dataList = (new BusinessTableExcellor(table)).toExcel(list);


        List<String> lmNames = new ArrayList<>();
        for (String lk : lmKeys) {
            IBusinessColumn column = table.getColumnByKey(lk);
            if (column != null) {
                lmNames.add(column.getComment());
                writer.addHeaderAlias(column.getKey(), column.getComment());
            } else {
                lmNames.add(lk);
                writer.addHeaderAlias(lk, lk);
            }
        }
        if (list.isEmpty()) {
            writer.writeHeadRow(lmNames);
        }

        List<Map<String, Object>> dl = new ArrayList<>();
        dataList.forEach(data -> {
            Map<String, Object> d = new LinkedHashMap<>();
            for (String lk : lmKeys) {
                d.put(lk, data.get(lk));
            }
            dl.add(d);
        });
        writer.write(dl);


        String downloadFileName = new String(table.getComment().getBytes("UTF-8"), "iso-8859-1");
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + downloadFileName + ".xls");
        ServletOutputStream servletOutputStream = response.getOutputStream();
        writer.flush((OutputStream) servletOutputStream);

        writer.close();

        IoUtil.close((Closeable) servletOutputStream);
    }


    public static void main(String[] args) {
        Map<String, Object> row1 = new LinkedHashMap<>();
        row1.put("name", "张三");
        row1.put("examDate", DateUtil.date());
        row1.put("age", Integer.valueOf(23));
        row1.put("score", Double.valueOf(88.32D));
        row1.put("isPass", Boolean.valueOf(true));

        ArrayList<Map<String, Object>> rows = CollUtil.newArrayList(new Map[]{row1});

        ExcelWriter writer = ExcelUtil.getWriter("d:/writeMapTest.xls");

        writer.addHeaderAlias("name", "姓名");
        writer.addHeaderAlias("age", "年龄");
        writer.addHeaderAlias("score", "分数");
        writer.addHeaderAlias("isPass", "是否通过");
        writer.addHeaderAlias("examDate", "考试时间");

        writer.merge(row1.size() - 1, "一班成绩单");

        writer.write(rows);

        writer.close();
    }
}
